import os.path

from tools import MuTool


class MuImages:
    def __init__(self):
        self.tools = MuTool()
        self.message = None
        self.os = self.tools.get_os()
    # 获取错误信息
    def get_error_message(self):
        return self.message
    # 分割图片
    def __split_image(self, input_image_path:str|list, output_image_path:str|None=None, img_type:str|None=None):
        from PIL import Image,ImageSequence
        try:
            if isinstance(input_image_path,str):
                input_image_path = input_image_path.split(",")
            images = []
            for path in input_image_path:
                with Image.open(path) as img:
                    if img.is_animated:
                        images.extend([frame.copy() for frame in ImageSequence.Iterator(img)])
                    else:
                        images.append(img.copy())
            img_type = str.lower(img_type)
            upstr = str.upper(img_type)
            for i, frame in enumerate(images):
                frame.save(f"{output_image_path}/{i}.{img_type}", upstr)
        except Exception as e:
            self.message = str(e)
            return False
        return True
    # Windows 压缩图片
    def __imgaes_to_imgages(self,input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None):
        from PIL import Image,ImageSequence
        if img_type=="jpg":
            img_type = "jpeg"
        img_type = str.upper(img_type)
        if isinstance(input_image_path,str):
            input_image_path = input_image_path.split(",")
        # print(input_image_path,output_image_path,type)
        if output_image_path and img_type and os.path.isdir(output_image_path):
            return self.__split_image(input_image_path, output_image_path, img_type)
        try:
            if img_type=="JPEG":
                img = Image.open(input_image_path[0])
                img.convert("RGB").save(output_image_path,img_type)
            elif img_type=="PNG":
                img = Image.open(input_image_path[0])
                img.convert("RGBA").save(output_image_path,img_type)
            elif img_type=="BMP":
                img = Image.open(input_image_path[0])
                img.save(output_image_path, format='BMP')
            elif img_type=="GIF":
                images = []
                for path in input_image_path:
                    with Image.open(path) as img:
                        # 如果图片是GIF，则加载所有帧
                        if img.is_animated:
                            images.extend([frame.copy() for frame in ImageSequence.Iterator(img)])
                        else:
                            images.append(img.copy())
                duration = 3
                images[0].save(
                    output_image_path,
                    save_all=True,
                    append_images=images[1:],
                    duration=duration,  # 设置每帧的持续时间（毫秒）
                    loop=0  # 0表示无限循环
                )
            elif img_type=="ICO":
                img = Image.open(input_image_path[0])
                img.save(output_image_path, format='ICO')
        except Exception as e:
            self.message = str(e)
            return False
        return True
    # 转换图片类型
    def convert_type(self,input_image_path:str|list, output_path:str|None=None,img_type:str|None=None):
        '''
        :param input_image_path: 输入文件
        :param output_path: 输出文件或者文件夹【gif提取图片时传文件夹】
        :param type: 转换类型
        :return:
        '''
        if not output_path and not img_type:
            self.message = '输出图片路径和类型不能同时为空'
            return False
        if not img_type:
            strArray = output_path.split(".");
            img_type = strArray[len(strArray)-1]
        if img_type in ['jpg','jpeg','png','gif','bmp','ico']:
            return self.__imgaes_to_imgages(input_image_path, output_path,img_type)
        pass
    # 压缩图片
    def compress_image(self,input_image_path:str, output_image_path:str|None=None, quality:str|int|float|None=None,max_size:str|int|float|None=None,width:str|int|float|None=None,height:str|int|float|None=None):
        '''

        :param input_image_path: 输入图片
        :param output_image_path: 输出图片
        :param quality: 压缩的程度0-100
        :param max_size: 压缩到的大小单位b
        :param width: 压缩到的宽度
        :param height: 压缩到的高度
        :return:
        '''
        if not os.path.exists(input_image_path):
            self.message = '输入图片不存在'
            return False
        if self.tools.is_empty(output_image_path):
            output_image_path = self.tools.get_md5()
            _, file_extension = os.path.splitext(input_image_path)
            output_image_path = output_image_path + file_extension
        if self.os == 'win':
            return self.__widnows_compress(input_image_path, output_image_path, quality,max_size,width,height)
        if self.os == 'linux':
            return self.__linux_compress(input_image_path, output_image_path, quality,max_size,width,height)
        if self.os == 'mac':
            return self.__mac_compress(input_image_path, output_image_path, quality,max_size,width,height)
        self.message = '系统不支持'
        return False
    # Mac 压缩图片
    def __mac_compress(self,input_image_path:str, output_image_path:str|None=None, quality:str|int|float|None=None,max_size:str|int|float|None=None,width:str|int|float|None=None,height:str|int|float|None=None):
        return self.__widnows_compress(input_image_path, output_image_path, quality,max_size,width,height)
    # Linux 压缩图片
    def __linux_compress(self,input_image_path:str, output_image_path:str|None=None, quality:str|int|float|None=None,max_size:str|int|float|None=None,width:str|int|float|None=None,height:str|int|float|None=None):
        return self.__widnows_compress(input_image_path, output_image_path, quality,max_size,width,height)
    # 图片压缩
    def __imgresize(self,input_image_path:str, output_image_path:str|None=None, max_size:str|int|float|None=None,quality=95,up_size=0):
        from PIL import Image
        image = Image.open(input_image_path)
        if os.path.exists(output_image_path):
            os.remove(output_image_path)
        image.save(output_image_path, quality=quality)
        size = os.path.getsize(output_image_path)
        if up_size == 0:
            up_size = size
        else:
            # 判断图片大小是否相等
            if size == up_size:
                #相等表示不可压缩
                bili = size/max_size
                width = int(image.size[0] / bili)
                height = int(image.size[1] / bili)
                image = image.resize((width, height))
                image.save(output_image_path)
                return True
        if os.path.getsize(output_image_path) > max_size:
            # print(os.path.getsize(output_image_path))
            os.remove(output_image_path)
            quality -= 5
            return self.__imgresize(input_image_path, output_image_path, max_size,quality,up_size)
        return True
    # Windows 压缩图片
    def __widnows_compress(self,input_image_path:str, output_image_path:str|None=None, quality:str|int|float|None=None,max_size:str|int|float|None=None,width:str|int|float|None=None,height:str|int|float|None=None):
        from PIL import Image
        try:
            if max_size:
                max_size = int(max_size)
                return self.__imgresize(input_image_path, output_image_path, max_size)
            image = Image.open(input_image_path)
            if quality:
                quality = int(quality)
                image.save(output_image_path, quality=quality)
                return True
            if width or height:
                proportion = image.size[0] / image.size[1]
                if width:
                    width = int(width)
                    height = int(width / proportion)
                elif height:
                    height = int(height)
                    width = int(height * proportion)
                elif width and height:
                    width = int(width)
                    height = int(height)
                image = image.resize((width, height))
                image.save(output_image_path)
                return True
        except Exception as e:
            self.message = str(e)
            return False
        return True
    # 拼接图片
    def splicing_images(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        '''

        :param input_image_path: 输入图片地址
        :param output_image_path: 输出图片地址
        :param img_type: 转换的类型
        :param horizontal: 是否横向：1=是，0=否
        :param side: 局左/上/右/下
        :param margins:边距
        :param spacing:间距
        :param background:背景色(png=(255,255,255,0),jpg=(255,255,255))
        :return:
        '''
        if isinstance(input_image_path,str):
            input_image_path = input_image_path.split(',')
        if not img_type in ['png','jpeg','jpg','ico','bmp']:
            if img_type in ['word','ppt','pptx','excel','xlsx','doc','docx','pdf']:
                return self.__splicing_images_opther(input_image_path, output_image_path,img_type,horizontal,side,margins,spacing,background)
            else:
                self.message = '不支持的图片类型'
                return False
        from PIL import Image
        try:
            if self.tools.is_empty(horizontal):
                horizontal = 0
            if self.tools.is_empty(margins):
                margins = 0
            else:
                margins = int(margins)
            if self.tools.is_empty(spacing):
                spacing = 0
            else:
                spacing = int(spacing)
            if self.tools.is_empty(img_type):
                img_type = 'png'
            if self.tools.is_empty(input_image_path):
                self.message = '输入图片不能为空'
                return False
            if self.tools.is_empty(background):
                if img_type == 'png':
                    background = (255,255,255,0)
                else:
                    background = (255,255,255)
            images = []
            widths = []
            heights = []
            for image_path in input_image_path:
                if not os.path.exists(image_path):
                    self.message = '输入图片不存在'
                    return False
                nimg = Image.open(image_path)
                images.append(nimg)
                widths.append(nimg.size[0])
                heights.append(nimg.size[1])
            max_width = max(widths)
            max_height = max(heights)
            if horizontal==0:
                all_width = int(max(widths)+margins*2)
                all_height = int(sum(heights)+spacing*(len(images))+margins*2)
            else:
                all_width = int(sum(widths)+spacing*(len(images))+margins*2)
                all_height = int(max(heights)+margins*2)
            if img_type=="png":
                mode = 'RGBA'
            elif img_type=="jpg" or img_type=="jpeg":
                mode = 'RGB'
            elif img_type=="ico":
                mode = 'RGBA'
            elif img_type=="bmp":
                mode = 'RGB'
            else:
                mode = 'RGBA'
            if self.tools.is_empty(side):
                side = 'center'
            new_im = Image.new(mode, (all_width, all_height), background)
            if horizontal==0:
                n_width = margins
                n_height = spacing
            else:
                n_width = spacing
                n_height = margins
            for i, im in enumerate(images):
                if horizontal==0:
                    if side=='center':
                        new_im.paste(im, (n_width+(max_width-im.size[0])//2, n_height))
                    if side=='left' or side=='top':
                        new_im.paste(im, (margins, n_height))
                    if side=='right' or side=='bottom':
                        new_im.paste(im, (margins, n_height))
                    n_height += im.size[1]+spacing
                elif horizontal==1:
                    if side=='center':
                        new_im.paste(im, (n_width, (max_height-im.size[1])//2+margins))
                    if side=='left' or side=='top':
                        new_im.paste(im, (n_width, margins))
                    if side=='right' or side=='bottom':
                        new_im.paste(im, (n_width,  (max_height-im.size[1]+margins)))
                    n_width += im.size[0]+spacing
            new_im.save(output_image_path)
        except Exception as e:
            self.message = str(e)
            return False
        return True
    # 其他格式
    def __splicing_images_opther(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        # return self.__image_to_pdf(input_image_path, output_image_path,type,horizontal,side,margins,spacing,background)
        try:
            if img_type=="pptx" or img_type=="ppt":
                return self.__image_to_pptx(input_image_path, output_image_path,img_type,horizontal,side,margins,spacing,background)
            elif img_type=="word" or img_type=="doc" or img_type=="docx":
                return self.__image_to_docx(input_image_path, output_image_path,img_type,horizontal,side,margins,spacing,background)
            elif img_type=="excel" or img_type=="xlsx":
                return self.__image_to_excel(input_image_path, output_image_path,img_type,horizontal,side,margins,spacing,background)
            elif img_type=="pdf":
                return self.__image_to_pdf(input_image_path, output_image_path,img_type,horizontal,side,margins,spacing,background)
        except Exception as e:
            self.message = str(e)
            return False
        return True
    def __get_image_size(self,filePath):
        from PIL import Image
        image = Image.open(filePath)
        return image.size
    # pdf
    def __image_to_pdf(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        import fitz
        doc = fitz.open()
        margins_num = int(margins)
        spacing_num = int(spacing)
        for file in input_image_path:
            width,height = self.__get_image_size(file)
            width_al = int(width+margins_num)
            height_al = int(height+spacing_num)
            img_rect = fitz.Rect(int(margins_num), int(spacing_num), width, height)
            page = doc.new_page(width=width_al, height=height_al)
            page.insert_image(img_rect, filename=file)
        doc.save(output_image_path)
        doc.close()
        return True
    def __resize_image(self,image_path, max_height_px, output_path):
        from PIL import Image
        image = Image.open(image_path)
        original_width, original_height = image.size
        # print(original_width,original_height)
        if original_height > max_height_px:
            # Calculate new width to maintain aspect ratio
            aspect_ratio = max_height_px / original_height
            # print(aspect_ratio)
            new_width = int(aspect_ratio * original_width)
            new_height = int(aspect_ratio * original_height)
            # print(new_width,new_height)
            resized_img = image.resize((new_width, new_height))
            # resized_img = img.resize((new_width, new_height))
            resized_img.save(output_path)
            return output_path,new_width, new_height
            # return output_path  # Return the path to the resized image
        else:
            return image_path,original_width, original_height  # No resize needed, return the ori
    def __image_to_excel(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        from openpyxl import Workbook
        from openpyxl.drawing.image import Image
        from PIL import Image as PilImage
        import time
        wb = Workbook()
        ws = wb.active
        start_cell = "A1"
        max_height_px = 500
        row_idx = 1  # Starting row index based on start_cell
        col_idx = ord(start_cell[0]) - ord('A') + 1  # Starting column index based on start_cell's column letter

        resized_image_paths = []  # To store paths to resized images (if any)
        widths = []
        for image_path in input_image_path:
            # Resize the image if necessary
            md5str = MuTool.get_md5(str(time.time()*1000))
            newpath = f'./imgtems/{md5str}.{image_path.rsplit(".", 1)[1]}'
            if not os.path.exists("./imgtems"):
                os.makedirs("./imgtems", exist_ok=True)

            resized_image_path, img_width_px, img_height_px = self.__resize_image(image_path, max_height_px,newpath )

            resized_image_paths.append(resized_image_path)
            widths.append(img_width_px)
            # Convert row and column indices to Excel cell reference
            cell_ref = f'{chr(col_idx + ord("A") - 1)}{row_idx}'

            img = Image(resized_image_path)
            img.anchor = cell_ref

            ws.add_image(img)

            extra_space_pt = 10  # Extra space in points
            img_height_px = PilImage.open(resized_image_path).size[1]  # Get the height of the resized image in pixels
            img_height_pt = img_height_px / 96 * 72  # Convert pixels to points
            ws.row_dimensions[row_idx].height = img_height_pt + extra_space_pt
            row_idx += 1
        ws.column_dimensions[chr(col_idx + ord("A") - 1)].width = int(max(widths)/7)
        wb.save(output_image_path)
        if os.path.exists("./imgtems"):
            MuTool.delete_path("./imgtems")
        return True
    # docx
    def __image_to_docx(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        from docx import Document
        from docx.shared import Inches
        doc = Document()
        for image_path in input_image_path:
            if not os.path.exists(image_path):
                self.message = '输入图片不存在'
                return False
            doc.add_picture(image_path, width=Inches(6.0))
            doc.add_paragraph('')
        doc.save(output_image_path)
        return True
    # pptx
    def __image_to_pptx(self, input_image_path:str|list, output_image_path:str|None=None,img_type:str|None=None,horizontal:str|int|None=None,side:str|None=None,margins:str|int|float|None=None,spacing:str|int|float|None=None,background:tuple|None=None):
        from PIL import Image
        from pptx import Presentation
        from pptx.util import Inches
        if self.tools.is_empty(horizontal):
            horizontal = 0
        if self.tools.is_empty(margins):
            margins = 0
        else:
            margins = int(margins)
        if self.tools.is_empty(spacing):
            spacing = 0
        else:
            spacing = int(spacing)
        if self.tools.is_empty(img_type):
            img_type = 'png'
        if self.tools.is_empty(input_image_path):
            self.message = '输入图片不能为空'
            return False
        if isinstance(input_image_path,str):
            input_image_path = input_image_path.split(',')
        if self.tools.is_empty(background):
            if img_type == 'png':
                background = (255,255,255,0)
            else:
                background = (255,255,255)
        images = []
        widths = []
        heights = []
        for image_path in input_image_path:
            if not os.path.exists(image_path):
                self.message = '输入图片不存在'
                return False
            nimg = Image.open(image_path)
            images.append(nimg)
            widths.append(nimg.size[0])
            heights.append(nimg.size[1])
        prs = Presentation()
        margins = Inches(margins/25.4)
        spacing = Inches(spacing/25.4)
        # print(margin)
        slide_layout = prs.slide_layouts[5]  # 使用空白布局（索引5）
        for i, img in enumerate(images):

            slide = prs.slides.add_slide(slide_layout)
            for shape in slide.shapes:
                placeholder_format = shape.placeholder_format
            if placeholder_format.type == 1:  # 标题占位符
                sp = shape._element
                sp.getparent().remove(sp)
            elif placeholder_format.type == 2:  # 副标题占位符
                sp = shape._element
                sp.getparent().remove(sp)
            slide_width = prs.slide_width
            slide_height = prs.slide_height
            aspect_ratio = img.size[1] / img.size[0]
            if aspect_ratio > slide_height / slide_width:
                # 图片相对于幻灯片更“高”，按高度缩放
                scaled_height = slide_height-margins
                scaled_width = int(scaled_height / aspect_ratio)-spacing

            else:
                # 图片相对于幻灯片更“宽”，按宽度缩放
                scaled_width = slide_width-margins
                scaled_height = int(aspect_ratio * scaled_width)-spacing
            # print(margins,spacing)
            left = (slide_width - scaled_width) / 2
            top = (slide_height - scaled_height) / 2
            slide.shapes.add_picture(input_image_path[i], left, top, scaled_width, scaled_height)
        prs.save(output_image_path)
        return True


